package com.itheima.userservice.rabbitmq;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.userservice.bean.MsgVo;
import com.itheima.userservice.service.MsgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.Objects;
import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/rabbit")
public class RabbitMQSendMsgController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private MsgService msgService;

    @PostMapping("/ordinary")
    public void rabbitTest(@RequestBody Map map) throws JsonProcessingException {

        String orderUUID = UUID.randomUUID().toString();

        // 创建 ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper();
        String msg = objectMapper.writeValueAsString(map);
        log.debug("接收到的参数已经转换为了:" + msg);


        //todo::把需要发送的消息插入到db,并将状态设置为为发送
        MsgVo msgVo = new MsgVo();
        msgVo.setExchange("user_exchange_001");
        msgVo.setMessage(msg);
        msgVo.setStatus("1");
        msgVo.setUuid(orderUUID);
        msgService.add(msgVo);
//        //todo::bug--关闭以下设置因为存在重复发送消息就报错的情况，暂时不清楚具体解决方案
//        //设置关联消息
//        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
//
//        //方法用于设置消息发送到交换机后的确认回调函数
//        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
//            @Override
//            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
//                //这里的关联消息是上面设置的
//                System.out.println("=============confirmCallBack触发。消息到达MQ===========");
//                if (ack) {
//                    if (correlationData != null) {
//                        System.out.println(correlationData.getId());
//                    }
//                    if (cause != null) {
//                        System.out.println(cause);
//                    }
//                } else {
//                    System.out.println(cause);
//                }
//            }
//        });
//
//        //异常时的恢复回调函数
//        rabbitTemplate.setRecoveryCallback(new RecoveryCallback<Object>() {
//            @Override
//            public Object recover(RetryContext retryContext) throws Exception {
//                System.out.println("异常时的恢复成功");
//                return null;
//            }
//        });
//
//        //设置消息无法被路由到目标队列时的回调函数
//        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
//            @Override
//            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
//
//            }
//        });
        /*
         *关联消息的作用:
         *    1、消息确认机制
         *    2、消息幂等性
         *    3、异步处理的结果关联
         *    4、日志追踪和故障排查
         */
        CorrelationData correlationData = new CorrelationData(orderUUID);
        System.out.println("生成的订单id=== > " + orderUUID);

        //这里会出现是不一致的问题
//        MessageProperties properties = new MessageProperties();
//        properties.setMessageId(UUID.randomUUID().toString());
//        Message message = new Message(msg.getBytes(),properties);

        //知识点rabbtmq的消息幂等性:这是正确的幂等性

        Message build = MessageBuilder.withBody(msg.getBytes()).setContentEncoding("utf-8")
                .setContentType(MessageProperties.CONTENT_TYPE_JSON).setMessageId(orderUUID)
                //下一行代码也可以注释掉,但是消费者就接收不到这个关联消息id了
                .setCorrelationId(orderUUID)
                .build();

        //这样就是绑定不到消息id的,消费者提示是null
        //Message build = MessageBuilder.withBody(msg.getBytes()).build();
        rabbitTemplate.convertAndSend("user_exchange_001", "cn", build, correlationData);
    }

    @PostMapping("/dead/exchange")
    public void rabbitDeadExchange(@RequestBody Map map) throws JsonProcessingException {

        // 创建 ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper();
        String msg = objectMapper.writeValueAsString(map);

        //Message build = MessageBuilder.withBody(msg.getBytes()).build();

        rabbitTemplate.convertAndSend("user_exchange_001", "cn", msg);
    }

}
